#include "parser.h"

namespace BioParser
{

    Parser::Parser(float p,
                   std::map<std::string, GenericRules> lexeme_dict,
                   std::vector<std::string> all_areas,
                   std::vector<std::string> initial_areas,
                   std::vector<std::string> recurrent_areas) : Brain(p, 0.5, 6666)
    {
        lexeme_dict_ = lexeme_dict;
        all_areas_ = all_areas;
        initial_areas_ = initial_areas;
        recurrent_areas_ = recurrent_areas;
    }

    void Parser::ActivateWord(std::string area_name, std::string word)
    {
        int k = getAreaByName(area_name).k_winners_;
        int begin = lexeme_dict_[word].index * k;
        Fire(area_name, begin, begin + k);
        FixAssembly(area_name);
    }

    std::string Parser::GetWord(std::string area_name, float threshold)
    {
        Komari::Area &tag_area = getAreaByName(area_name);
        if (tag_area.winners_[0] < -1)
        {
            std::cerr << "GetWord() failed cause no assembly inside of area: " << area_name << std::endl;
            exit(0);
        }
        auto winners = tag_area.winners_;
        std::sort(winners.begin(), winners.end());

        for (auto ele : lexeme_dict_)
        {
            int word_index = ele.second.index;
            std::vector<int> range, v;
            int assembly_begin = word_index * tag_area.k_winners_;

            for (size_t i = assembly_begin; i < assembly_begin + tag_area.k_winners_; i++)
                range.push_back(i);

            std::set_intersection(winners.begin(), winners.end(), range.begin(), range.end(), std::back_inserter(v));
            // if (ele.first == "bad") {
            //     printf("bad size: %d ", v.size());
            //     std::cout << area_name << std::endl;
            // }
            if (v.size() >= threshold * tag_area.k_winners_)
                return ele.first;
        }

        return "<Not A Word>";
    }

    void Parser::RememberFibers(std::map<std::string, std::vector<std::string>> proj_map)
    {
        for (auto ele : proj_map)
        {
            auto it = activated_fibers_.find(ele.first);
            if (it == activated_fibers_.end())
                activated_fibers_[ele.first] = {};

            for (auto s : ele.second)
                it->second.insert(s);
        }
    }

    void Parser::Step()
    {
        auto proj_map = GetProjectMap();

        ProjectStar(proj_map);
    }

    void Parser::ApplyRules(AreaAndFiberRules rules)
    {
        for (AreaRule rule : rules.area_rules)
            ApplyAreaRule(rule.name, rule.inhibit, rule.population);
        for (FiberRule rule : rules.fiber_rules)
            ApplyFiberRule(rule.first_name, rule.second_name, rule.inhibit, rule.population);
    }

    void Parser::Initiate()
    {
        InhibitAllAreas(true, 0);
        InhibitAllFibers(0);

        // 除了初始脑区的脑区一开始都应当被抑制。
        for (auto name : initial_areas_)
            getAreaByName(name).applyRule(false, 0);
    }

    void Parser::UnfixAllAreas()
    {
        for (std::string area : all_areas_)
            UnfixAssembly(area);
    }

} // namespace BioParser
